package au.com.bus4u.controller.pc;


import au.com.bus4u.controller.BaseController;
import au.com.bus4u.dao.DaoSupport;
import au.com.bus4u.exception.PseudoLoginSuccessException;
import au.com.bus4u.exception.ServiceException;
import au.com.bus4u.service.OrderService;
import au.com.bus4u.service.UserService;
import au.com.bus4u.utils.CodeUtil;
import au.com.bus4u.utils.JsonResult;
import au.com.bus4u.utils.PageData;
import lombok.extern.java.Log;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.RenderedImage;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
@RequestMapping("/pc/user")
@Log
public class UserController extends BaseController {
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private UserService userService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private DaoSupport daoSupport;

    @Value("${openCode}")
    private boolean openCode;//是否开启验证码

    @ResponseBody
    @RequestMapping("/login")
    public JsonResult<Map> login(String phone, String password, String code)throws Exception{
        log.info("==========================执行登陆==========================");
        //System.out.println("user_email = [" + user_email + "], password = [" + password + "], code = [" + code + "]");
        PageData requestPD = getPageData();
        HttpSession session = request.getSession();
        Map<String, Object> result = new HashMap<>();

        if(openCode){
//            System.err.println("浏览器请求来的session中的验证码为:"+session.getAttribute("code"));
            if( session.getAttribute("code") == null) throw new ServiceException("验证码已过期,请重新输入新的验证码！");
//            System.err.println(session.getAttribute("code").toString().equalsIgnoreCase(code));
            //对比 验证码
            if(!session.getAttribute("code").toString().equalsIgnoreCase(code)) throw new ServiceException("Code incorrect!");
//            System.err.println(session.getAttribute("code"));
        }

        List<PageData> byPhone = userService.findByPhone(phone);
        PageData currentUser = null;
        String salt = "";
        if(byPhone.size()>0){
            currentUser = byPhone.get(0);


            //获取当前用户的old_status 登陆合并来的旧用户数据
            if(currentUser.get("old_status") != null){
//                System.err.println("old_status="+currentUser.get("old_status"));
                int old_status = currentUser.getInt("old_status");

                checkOldUserStatus(old_status,currentUser,password);//验证合并来的旧用户数据

            }



            salt = currentUser.get("salt").toString();
        }
        Subject subject = SecurityUtils.getSubject();
//        System.err.println("原始密码："+password);
//        System.err.println("加密密码："+getMd5Password(password,salt));
        UsernamePasswordToken token = new UsernamePasswordToken(phone,getMd5Password(password,salt));
//        UsernamePasswordToken token = new UsernamePasswordToken(phone,password);

        subject.login(token);//执行shiro的登陆


        currentUser = userService.parseUserInfo(currentUser);

        //把当前用户信息存到session中(包含对应角色附加数据)
//        System.err.println("currentUser:"+currentUser);
        SecurityUtils.getSubject().getSession().setAttribute("currentUser", currentUser);

        List<PageData> orderStatusCodeList = orderService.findOrderStatusCodeList();
//        System.out.println("orderStatusCodeList = " + orderStatusCodeList);
//        log.info(orderStatusCodeList.size());

        SecurityUtils.getSubject().getSession().setAttribute("orderStatusCodeList", orderStatusCodeList);
        result.put("orderStatusCodeList",orderStatusCodeList);
        //保存最后次登陆时间、IP
        PageData lastLogin = new PageData();
        lastLogin.put("user_id",currentUser.get("user_id"));
        lastLogin.put("role_id",currentUser.get("role_id"));
        lastLogin.put("last_login_time",new Date());
        lastLogin.put("last_login_ip",requestPD.getIpAddress());
        userService.edit(lastLogin);//登陆成功 执行保存最后次登陆时间和最后次登陆IP

        return new JsonResult<Map>(SUCCESS, result);
    }


    /**
     * 注册
     * /pc/user/regist
     * @return
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping("/regist")
    public JsonResult<Map> regist()throws Exception{
        log.info("=========================================");
        Map<String, Object> result = new HashMap<>();
        PageData pageData = getPageData();
//        System.err.println("UserController.regist");
//        System.err.println("pageData = " + pageData);

        userService.save(pageData);

        return new JsonResult<Map>(SUCCESS, result);
    }
    /**
     * 旧用户数据补全
     * /pc/user/oldUserInfoSupplement
     * @return
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping("/oldUserInfoSupplement")
    public JsonResult<Map> oldUserInfoSupplement()throws Exception{
        log.info("=========================================");
        Map<String, Object> result = new HashMap<>();
        PageData pageData = getPageData();
//        System.err.println("UserController.oldUserInfoSupplement");
//        System.err.println("pageData = " + pageData);

        userService.oldUserInfoSupplement(pageData);//旧用户数据补全

        return new JsonResult<Map>(SUCCESS, result);
    }

    /**
     * @修改用户信息
     * @return
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping("/update")
    public JsonResult<Map> update()throws Exception{
        log.info("=========================================");
        Map<String, Object> result = new HashMap<>();
        PageData pageData = getPageData();
//        System.err.println("pageData = " + pageData);

        userService.edit(pageData);

        updataSessionUser();//更新sesssion中的当前登录用户数据
        return new JsonResult<Map>(SUCCESS, result);
    }












    /**
     * 后台产生验证码
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @RequestMapping("/getCode")
    public void getCode(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
    {
        log.info("=========================================");
        // 调用工具类生成的验证码和验证码图片
        Map<String, Object> codeMap = CodeUtil.generateCodeAndPic();

        // 将四位数字的验证码保存到Session中。
        HttpSession session = req.getSession();
        String code = codeMap.get("code").toString();
        session.setAttribute("code",code);
//        System.err.println("服务器验证码:"+code);
        // 禁止图像缓存。
        resp.setHeader("Pragma", "no-cache");
        resp.setHeader("Cache-Control", "no-cache");
        resp.setDateHeader("Expires", -1);
        resp.setContentType("image/jpeg");

        // 将图像输出到Servlet输出流中。
        ServletOutputStream sos;
        try
        {
            sos = resp.getOutputStream();
            ImageIO.write((RenderedImage) codeMap.get("codePic"), "jpeg", sos);
            sos.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }

    }


    /**
     * 	 对密码进行加密
     * @param password 原始密码
     * @param salt 盐值
     * @return 加密后的密码
     */
    private static String getMd5Password(String password,String salt) {
        // salt+password+salt 进行3次加密
        String msg=salt+password+salt;
        for(int i=0;i<3;i++) {
            msg= DigestUtils.md5DigestAsHex(msg.getBytes());
        }
        return msg;
    }


    private void updataSessionUser() throws Exception {
//        System.err.println("UserController.updataSessionUser");
        String currentUserID = getCurrentUserID();
        PageData currentUser = userService.findById(currentUserID);

        currentUser = userService.parseUserInfo(currentUser);

        //把当前用户信息存到session中(包含对应角色附加数据)
//        System.err.println("currentUser:"+currentUser);
        SecurityUtils.getSubject().getSession().setAttribute("currentUser", currentUser);
    }


    /**
     * 验证合并来的旧用户数据
     */
    private void checkOldUserStatus(int old_status,PageData currentUser,String old_password) throws Exception{

        switch(old_status){
            case 0:
                //初始状态 密码未加密 角色id未初始化 邮箱未验证

                //将电话后6位数字修改加密 初始化盐值 初始化用户角色 修改old_status状态至1 保存数据库
                String salt = get32UUID();
                //password salt role_id
                String phone = currentUser.getString("phone");
                String password = phone.substring(phone.length()-6);//截取电话后6位数字为加密前的密码
                password = getMd5Password(password,salt);

                //初始化角色
                String avatar = currentUser.getString("avatar");
                int role_id = 5;
                if("user".equals(avatar)){
                    role_id = 5;
                }
                if("driver".equals(avatar)){
                    role_id = 4;
                }
                if("manager".equals(avatar)){
                    role_id = 2;
                }
                currentUser.put("salt",salt);
                currentUser.put("password",password);
                currentUser.put("role_id",role_id);
                currentUser.put("old_status",1);
                currentUser.put("status",2);
                daoSupport.update("UserMapper.edit", currentUser);

                checkOldUserStatus(1,currentUser,old_password);

                break;
            case 1:
                //密码 盐值已初始化 默认为phone后6位

                //伪登陆-密码正确则跳转用户数据补全页面
                pseudoLogin(currentUser,old_password);

                break;
            case 2:
                //数据已补全 执行正常登陆流程(验证邮箱在正常登陆流程内 无需再单独处理)

                break;
            default:
                break;
        }

    }
    /**
     * 伪登陆-密码正确则
     * 将oldUser保存到session中
     * 跳转用户数据补全页面
     */
    private void pseudoLogin(PageData currentUser, String old_password) {

//        System.err.println("登陆输入的密码: "+old_password);
        String encryption_password = getMd5Password(old_password,currentUser.getString("salt"));
//        System.err.println("登陆输入的密码加密后: "+encryption_password);
        String new_password = currentUser.getString("password");
//        System.err.println("用phone从数据中获取到的密码: "+new_password);
        if(!new_password.equals(encryption_password)){
            //登陆失败 抛出异常
//            System.err.println("伪登陆-失败:密码错误");
            throw new IncorrectCredentialsException();
        }else{
            //登陆成功 跳转旧用户数据补全页面
//            System.err.println("伪登陆-成功:跳转用户数据补全页面");

            try {
                currentUser = userService.parseUserInfo(currentUser);
            } catch (Exception e) {
                e.printStackTrace();
            }
            SecurityUtils.getSubject().getSession().setAttribute("oldUser", currentUser);
            throw new PseudoLoginSuccessException();
        }

    }
}
